/**
 * @file imgui_manager.cpp
 * @author jimingqing
 * @date 2023-04-16
 * @version 0.0.1
 * @copyright XiazhiTech Copyright (c) 2023
 *
 * @brief
 */

#include "ui/imgui_manager.h"
#include "render/render_system.h"

#include "imgui.h"
#include "backends/imgui_impl_glfw.h"
#include "backends/imgui_impl_opengl3.h"

namespace engine
{
    bool UIManager::init(GLFWwindow *nativeWindow)
    {
        this->nativeWindow = nativeWindow;
        frameBuffer = new FrameBuffer();

        // const char *glsl_version = "#version 410";
        const char *glsl_version = "#version 330";

        // Setup Dear ImGui context
        IMGUI_CHECKVERSION();
        ImGui::CreateContext();

        ImGuiIO &io = ImGui::GetIO();
        (void)io;
        io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
        io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;     // Enable Docking
        io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;   // Enable Multi-Viewport / Platform Windows

        // Setup Dear ImGui style
        // ImGui::StyleColorsDark();
        // ImGui::StyleColorsClassic();

        auto &colors = ImGui::GetStyle().Colors;
        colors[ImGuiCol_WindowBg] = ImVec4{0.1f, 0.1f, 0.1f, 1.0f};

        colors[ImGuiCol_Header] = ImVec4{0.2f, 0.2f, 0.2f, 1.0f};
        colors[ImGuiCol_HeaderHovered] = ImVec4{0.3f, 0.3f, 0.3f, 1.0f};
        colors[ImGuiCol_HeaderActive] = ImVec4{0.15f, 0.15f, 0.15f, 1.0f};

        colors[ImGuiCol_Button] = ImVec4{0.2f, 0.2f, 0.2f, 1.0f};
        colors[ImGuiCol_ButtonHovered] = ImVec4{0.3f, 0.3f, 0.3f, 1.0f};
        colors[ImGuiCol_ButtonActive] = ImVec4{0.15f, 0.15f, 0.15f, 1.0f};

        colors[ImGuiCol_FrameBg] = ImVec4{0.2f, 0.2f, 0.2f, 1.0f};
        colors[ImGuiCol_FrameBgHovered] = ImVec4{0.3f, 0.3f, 0.3f, 1.0f};
        colors[ImGuiCol_FrameBgActive] = ImVec4{0.15f, 0.15f, 0.15f, 1.0f};

        colors[ImGuiCol_Tab] = ImVec4{0.15f, 0.15f, 0.15f, 1.0f};
        colors[ImGuiCol_TabHovered] = ImVec4{0.38f, 0.38f, 0.38f, 1.0f};
        colors[ImGuiCol_TabActive] = ImVec4{0.28f, 0.28f, 0.28f, 1.0f};
        colors[ImGuiCol_TabUnfocused] = ImVec4{0.15f, 0.15f, 0.15f, 1.0f};
        colors[ImGuiCol_TabUnfocusedActive] = ImVec4{0.2f, 0.2f, 0.2f, 1.0f};

        colors[ImGuiCol_TitleBg] = ImVec4{0.15f, 0.15f, 0.15f, 1.0f};
        colors[ImGuiCol_TitleBgActive] = ImVec4{0.15f, 0.15f, 0.15f, 1.0f};
        colors[ImGuiCol_TitleBgCollapsed] = ImVec4{0.15f, 0.15f, 0.15f, 1.0f};

        ImGuiStyle &style = ImGui::GetStyle();
        if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
        {
            style.WindowRounding = 0.0f;
            style.Colors[ImGuiCol_WindowBg].w = 1.0f;
        }

        // Setup Platform/Renderer backends
        ImGui_ImplGlfw_InitForOpenGL(nativeWindow, true);
        ImGui_ImplOpenGL3_Init(glsl_version);
        RenderSystem::getInstance()->init();
        return true;
    }

    // void UIManager::onEvent(Event &event)
    // {
    //     // ImGui层收到事件开发分发出去
    //     // 引擎事件的流程 User->OpenGL->Application->Window->Layer
    //     // 开始派发全部ImGui需要的事件，将事件通知到ImGuiIO
    //     EventDispatcher dispatcher(event);
    //     dispatcher.Dispatch<MouseButtonPressedEvent>(AO_BIND_EVENT_FN(ImGuiLayer::OnMouseButtonPressedEvent));
    //     dispatcher.Dispatch<MouseButtonReleasedEvent>(AO_BIND_EVENT_FN(ImGuiLayer::OnMouseButtonReleasedEvent));
    //     dispatcher.Dispatch<MouseMovedEvent>(AO_BIND_EVENT_FN(ImGuiLayer::OnMouseMovedEvent));
    //     dispatcher.Dispatch<MouseScrolledEvent>(AO_BIND_EVENT_FN(ImGuiLayer::OnMouseScrolledEvent));
    //     dispatcher.Dispatch<KeyPressedEvent>(AO_BIND_EVENT_FN(ImGuiLayer::OnKeyPressedEvent));
    //     dispatcher.Dispatch<KeyTypedEvent>(AO_BIND_EVENT_FN(ImGuiLayer::OnKeyTypedEvent));
    //     dispatcher.Dispatch<KeyReleasedEvent>(AO_BIND_EVENT_FN(ImGuiLayer::OnKeyReleasedEvent));
    //     dispatcher.Dispatch<WindowResizeEvent>(AO_BIND_EVENT_FN(ImGuiLayer::OnWindowResizeEvent));
    // }

    void UIManager::render()
    {
        // Start the Dear ImGui frame
        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplGlfw_NewFrame();
        ImGui::NewFrame();

        // Create the docking environment
        ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar |
                                       ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
                                       ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus |
                                       ImGuiWindowFlags_NoBackground;

        ImGuiViewport *viewport = ImGui::GetMainViewport();
        ImGui::SetNextWindowPos(viewport->Pos);
        ImGui::SetNextWindowSize(viewport->Size);
        ImGui::SetNextWindowViewport(viewport->ID);

        ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
        ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
        ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
        ImGui::Begin("InvisibleWindow", nullptr, windowFlags);
        ImGui::PopStyleVar(3);

        ImGuiID dockSpaceId = ImGui::GetID("InvisibleWindowDockSpace");

        ImGui::DockSpace(dockSpaceId, ImVec2(0.0f, 0.0f), ImGuiDockNodeFlags_PassthruCentralNode);
        ImGui::End();

        // static bool isDemoWindowShow = true;
        // ImGui::ShowDemoWindow(&isDemoWindowShow);

        // Hierarchy
        {
            static float f = 0.0f;
            static int counter = 0;

            ImGui::Begin("Hierarchy");      // Create a window
            ImGui::Text("cube properties"); // Display some text (you can use a format strings too)

            // ImGui::Checkbox("IsRender", &cube1->isRender);
            // ImGui::DragFloat3("Position", (float *)&cube1->Position, 0.2f);
            // ImGui::DragFloat3("Rotate", (float *)&cube1->Rotate, 0.2f, -360.0f, 360.0f);
            // ImGui::DragFloat3("Scale", (float *)&cube1->Scale, 0.2f);
            // ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
            // ImGui::ColorEdit3("clear color", (float *)&cube1->Color); // Edit 3 floats representing a color

            if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
                counter++;
            ImGui::SameLine();
            ImGui::Text("counter = %d", counter);

            ImGui::End();
        }

        // Scene
        {
            ImGui::Begin("Scene");
            ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
            ImVec2 viewportPanelSize = ImGui::GetContentRegionAvail();
            frameBuffer->bind();
            glViewport(0, 0, 800, 600);
            glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            RenderSystem::getInstance()->processInput(this->nativeWindow);
            RenderSystem::getInstance()->render(1);
            frameBuffer->unbind();

            // mCamera->set_aspect(mSize.x / mSize.y);
            // mCamera->update(mShader.get());

            // // add rendered texture to ImGUI scene window
            ImGui::Image(reinterpret_cast<void *>(frameBuffer->get_texture()), ImVec2{viewportPanelSize.x, viewportPanelSize.y}, ImVec2{0, 1}, ImVec2{1, 0});

            ImGui::End();
        }

        // Inspector
        {
            ImGui::Begin("Inspector");

            ImGui::End();
        }

        // Log
        {
            ImGui::Begin("Log");

            ImGui::End();
        }

        // Rendering
        ImGui::Render();
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

        ImGuiIO &io = ImGui::GetIO();

        if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
        {
            GLFWwindow *backup_current_context = glfwGetCurrentContext();
            ImGui::UpdatePlatformWindows();
            ImGui::RenderPlatformWindowsDefault();
            glfwMakeContextCurrent(backup_current_context);
        }
    }
}
